<template>
  <g>
    <!-- 发光滤镜 -->
    <defs>
      <filter :id="`glow-${_uid}`" x="-100%" y="-100%" width="300%" height="300%">
        <feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur" />
        <feColorMatrix
          in="blur"
          mode="matrix"
          values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 25 -8"
          result="glow"
        />
        <feMerge>
          <feMergeNode in="glow" />
          <feMergeNode in="glow" />
          <feMergeNode in="SourceGraphic" />
        </feMerge>
      </filter>
      <!-- 渐变效果 -->
      <linearGradient :id="gradientId" x1="0%" y1="0%" x2="100%" y2="0%">
        <stop offset="0%" :stop-color="startColor" stop-opacity="1" />
        <stop offset="50%" :stop-color="startColor" stop-opacity="0.8" />
        <stop offset="100%" :stop-color="startColor" stop-opacity="0.4" />
      </linearGradient>
      <!-- 箭头标记定义 -->
      <marker
        :id="`arrow-${_uid}`"
        viewBox="0 0 10 10"
        refX="5"
        refY="5"
        markerWidth="6"
        markerHeight="6"
        orient="auto-start-reverse"
      >
        <path d="M 0 0 L 10 5 L 0 10 z" :fill="startColor" />
      </marker>
    </defs>
    <!-- 动画路径 -->
    <path
      :d="pathData"
      :stroke="`url(#${gradientId})`"
      :stroke-width="strokeWidth"
      fill="none"
      :style="{
        strokeDasharray: dashArray,
        strokeDashoffset: isAnimating ? 0 : dashOffset,
        transition: `stroke-dashoffset ${duration}ms linear`,
        animation: isAnimating
          ? `flowAnimation${_uid} ${duration}ms linear infinite`
          : 'none',
        animationDelay: `${delay}ms`,
      }"
    />
    <!-- 动画箭头 -->
    <path
      v-if="isAnimating && showArrow"
      d="M -2 -4 L 12 0 L -2 4 Z"
      :fill="startColor"
      :filter="`url(#glow-${_uid})`"
      fill-opacity="0.9"
      stroke-opacity="1"
      :stroke="startColor"
      stroke-width="1"
    >
      <animateMotion
        :dur="`${duration}ms`"
        :path="pathData"
        rotate="auto"
        repeatCount="indefinite"
        :begin="`${delay}ms`"
        keyPoints="0;1"
        keyTimes="0;1"
        calcMode="linear"
      >
        <animate
          attributeName="fill-opacity"
          values="0.4;0.9;0.4"
          :dur="`${duration}ms`"
          repeatCount="indefinite"
        />
      </animateMotion>
    </path>
  </g>
</template>

<script>
/**
 * @component DataFlowAnimation
 * @description 数据流动画组件 - 用于创建SVG路径上的流动动画效果
 * 该组件可以在SVG路径上创建流畅的数据流动画，支持自定义颜色、速度和发光效果
 * 主要用于可视化数据流动、网络连接等场景
 */
export default {
  name: "DataFlowAnimation",
  props: {
    /** SVG路径数据 - 定义动画的运动轨迹 */
    pathData: {
      type: String,
      required: true,
    },
    /** 动画持续时间(毫秒) - 控制动画完成一次循环的时间 */
    duration: {
      type: Number,
      default: 3000,
    },
    /** 流动效果颜色 - 定义动画的主要颜色 */
    startColor: {
      type: String,
      default: "#00ff00",
    },
    /** 线条宽度 - 定义路径的粗细 */
    strokeWidth: {
      type: Number,
      default: 2,
    },
    /** 流动效果长度 - 定义流动部分占整体路径的比例 */
    flowLength: {
      type: Number,
      default: 40,
    },
    /** 动画延迟时间(毫秒) - 定义动画开始前的等待时间 */
    delay: {
      type: Number,
      default: 0,
    },
    /** 是否自动开始动画 - 控制动画是否在挂载后自动播放 */
    autoPlay: {
      type: Boolean,
      default: true,
    },

    /** 是否显示箭头 - 控制是否显示动画箭头 */
    showArrow: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      /** 虚线数组 - 控制流动效果的虚线段长度 */
      dashArray: "0",
      /** 虚线偏移量 - 控制流动效果的位置 */
      dashOffset: "0",
      /** 渐变ID - 用于SVG渐变效果的唯一标识 */
      gradientId: `flow-gradient-${this._uid}`,
      /** 动画状态 - 控制动画的播放和暂停 */
      isAnimating: false,
    };
  },
  mounted() {
    // 组件挂载后初始化动画
    this.initAnimation();
    // 根据autoPlay属性决定是否自动开始动画
    if (this.autoPlay) {
      this.startAnimation();
    }
  },
  methods: {
    /**
     * 初始化动画配置
     * 计算路径长度，设置虚线样式，创建动画关键帧
     */
    initAnimation() {
      // 获取SVG路径元素并计算其总长度
      const path = this.$el.querySelector("path");
      const pathLength = path.getTotalLength();

      // 设置虚线样式，创建流动效果
      // flowLength决定流动部分的长度，剩余部分为间隔
      const flowGap = pathLength * 0.3; // 减小间隔，使动画更加连续
      this.dashArray = `${this.flowLength * 1.5} ${flowGap}`;
      this.dashOffset = pathLength;

      // 创建CSS动画样式
      const styleSheet = document.createElement("style");
      styleSheet.textContent = `
        @keyframes flowAnimation${this._uid} {
          0% {
            stroke-dashoffset: pathLength;
            stroke-opacity: 0.8;
          }
          50% {
            stroke-opacity: 1;
          }
          100% {
            stroke-dashoffset: -pathLength;
            stroke-opacity: 0.8;
          }
        }
        @keyframes arrowAnimation${this._uid} {
          from {
            offset-distance: 0%;
            opacity: 0.8;
          }
          to {
            offset-distance: 100%;
            opacity: 0.8;
          }
        }
      `;
      document.head.appendChild(styleSheet);

      // 创建动态箭头
      const arrow = document.createElementNS(
        "http://www.w3.org/2000/svg",
        "path"
      );
      arrow.setAttribute("d", "M 0 0 L 10 5 L 0 10 z");
      arrow.setAttribute("fill", this.startColor);
      arrow.setAttribute("filter", `url(#glow-${this._uid})`);
      arrow.style.offsetPath = `path('${this.pathData}')`;
      arrow.style.animation = `arrowAnimation${this._uid} ${this.duration}ms linear infinite`;
      arrow.style.animationDelay = `${this.delay}ms`;
      arrow.style.display = "none";
      this.$el.appendChild(arrow);

      // 保存箭头元素引用
      this.arrowElement = arrow;
    },
    /**
     * 开始动画
     * 设置isAnimating为true触发动画开始
     */
    startAnimation() {
      this.isAnimating = true;
    },
    /**
     * 停止动画
     * 设置isAnimating为false暂停动画
     */
    stopAnimation() {
      this.isAnimating = false;
    },
  },
};
</script>
